package com.qfmy.webapp.service.impl.user;

import com.qfmy.common.constant.RedisConstant;
import com.qfmy.common.exception.BaseException;
import com.qfmy.common.login.LoginUser;
import com.qfmy.common.login.LoginUserHolder;
import com.qfmy.common.result.ResultCodeEnum;
import com.qfmy.common.utils.CodeUtil;
import com.qfmy.common.utils.JwtUtil;
import com.qfmy.common.utils.QrCodeUtils;
import com.qfmy.model.entity.userInfo.UserInfo;
import com.qfmy.model.enums.BaseStatus;
import com.qfmy.model.query.user.UserQuery;
import com.qfmy.model.vo.user.LoginVo;
import com.qfmy.model.vo.user.UserInfoVo;
import com.qfmy.webapp.mapper.user.UserInfoMapper;
import com.qfmy.webapp.service.common.SmsService;
import com.qfmy.webapp.service.user.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


import java.awt.image.BufferedImage;
import java.math.BigDecimal;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author 清风明月
 * @Package com.qfmy.webapp.service.user.impl.user
 * @date 2025/11/11
 * @description 用户信息表
 */
@Slf4j
@Service
@SuppressWarnings("all")
public class UserInfoServiceImpl implements UserInfoService {

    /**
     * 注入默认的用户头像
     */
    @Value(value = "${default.avatar}")
    private String defaultAvatar;

    /**
     * 注入mapper
     */
    @Autowired
    private UserInfoMapper userInfoMapper;

    /**
     * 注入redisTemplate
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * RedisTemplate
     */
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 注入阿里云短信验证吗服务
     */
    @Autowired
    private SmsService smsService;

    /**
     * 获取短信验证码
     * @param phone
     */
    @Override
    public void getSmsCode(String phone) {
        //校验手机号
        checkPhone(phone);

        //随机生成6位短信验证码
        String code = CodeUtil.getRandomCode(6);
        log.info("发送验证码：{}", code);
        String key = RedisConstant.APP_LOGIN_PREFIX + phone;

        //判断是否已发送
        Boolean hasKey = stringRedisTemplate.hasKey(key);

        //存在
        if (hasKey) {
            //获取剩余时间
            Long ttl = stringRedisTemplate.getExpire(key, TimeUnit.SECONDS);
            //判断剩余时间是否小于60秒
            if (ttl > RedisConstant.APP_LOGIN_CODE_TTL_SEC - RedisConstant.APP_LOGIN_CODE_RESEND_TIME_SEC) {
                throw new BaseException(ResultCodeEnum.APP_SEND_SMS_TOO_OFTEN);
            }
        }

        //保存验证码
        stringRedisTemplate.opsForValue().set(key, code, RedisConstant.APP_LOGIN_CODE_TTL_SEC, TimeUnit.SECONDS);
//        //发送验证码
//       smsService.sendSms(phone, code);
    }

    /**
     * 手机号 + 验证码登入
     * @param userQuery
     * @return
     */
    @Override
    public LoginVo loginPhoneAndCode(@NotNull UserQuery userQuery) {
        //校验手机号
        checkPhone(userQuery.getPhone());

       //校验验证码
        checkCode(userQuery.getCode(), userQuery.getPhone());

        UserInfo userInfo = userInfoMapper.selectByPhone(userQuery.getPhone());
        if (userInfo == null) {
            //说明是新用户
            userInfo = CreatUserInfo(userQuery);
            userInfoMapper.insert(userInfo);
        }else {
            //校验状态
            checkStatus(userInfo);
            userInfo.setDeviceId(userQuery.getDeviceId());
            userInfo.setDeviceType(userQuery.getDeviceType());
            userInfo.setLastLoginIp(userQuery.getIp());
            userInfoMapper.update(userInfo, userQuery.getPhone());
        }

        //生成token
        String token = JwtUtil.createToken(userInfo.getUserId(),userInfo.getPhone());
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(userInfo, userInfoVo);
        return new LoginVo(token,userInfoVo);
    }

    /**
     * 获取临时登录令牌
     * @return
     */
    @Override
    public String getTempLoginToken() {
        //随机生成 -999999 - 0 之间的随机数
        Long userId = new Random().nextLong(-999999, 0);
        log.info("生成临时登录令牌：{}", userId);
        //生成token
        return JwtUtil.createToken(userId, "");
    }


    /**
     * 获取用户二维码
     * @return
     */
    @Override
    public String getUserQrCode() {
        //获取用户id
        Long userId = getUserId();
        //根据用户id查询信息
        UserInfo userInfo = userInfoMapper.getUserInfo(userId);
        //创建redis的key
        String key = "user_qr_code" + userId;
        //获取redis中的二维码
        String qrCode = stringRedisTemplate.opsForValue().get(key);
        //判断是否存在
        if (!StringUtils.hasText(qrCode)) {
            // 构建二维码内容
            String qrCodeContent = "用户ID:" + userId + ",用户名:" + userInfo.getUsername();
            //获取用户头像
            String avatar = userInfo.getAvatar();
            try {
                BufferedImage bufferedImage = QrCodeUtils.generateQrCodeWithLogo(qrCodeContent, avatar, null);
                qrCode = QrCodeUtils. bufferedImageToBase64(bufferedImage, "png");
                log.info("生成二维码成功！{}", qrCode);
                //保存二维码到redis并且设置过期时间为10小时
                stringRedisTemplate.opsForValue().set(key, qrCode,12, TimeUnit.HOURS);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return qrCode;
    }

    /**
     * 修改用户信息
     * @param userInfo
     */
    @Override
    public void updateUserInfo(UserInfo userInfo) {
       //获取用户的id
        Long userId = getUserId();
        //获取用户的手机号
        String phone = getPhone();
        userInfoMapper.update(userInfo,phone);
        //创建redis的key
        String key = "user_qr_code" + userId;
        //删除原来的二维码
        stringRedisTemplate.delete(key);
    }

    /**
     * 更新用户喜欢类型
     * @param categoryName
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserLikeType(String categoryName) {
        //获取用户id
        Long userId = getUserId();

        //判断用户id是否小于0
        if (userId > 0){
            //获取用户信息
            UserInfo userInfo = userInfoMapper.getUserInfo(userId);
            //获取喜欢类型
            String like = userInfo.getLikeType();
            //判断喜欢类型是否为空
            if(!StringUtils.hasText( like))
            {
                userInfo.setLikeType(categoryName);
                return;
            }
            String[] likeTypes = like.split(",");
            //循环判断是否存在
            for (String likeType : likeTypes) {
                if (likeType.equals(categoryName)){
                    return;
                }
                userInfo.setLikeType(userInfo.getLikeType() + "," + categoryName);
            }
            //更新用户信息
            userInfoMapper.updateLike(userId);
        }
    }

    /**
     * 修改用户阅读时间
     * @param time
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserReadTime(Integer time) {
        //获取用户id
        Long userId = getUserId();
        //判断用户id是否小于0
        if (userId < 0){
            return;
        }
        //创建缓存key
        String key = "today_read_time:" + userId;
        //从缓存中获取数据
        String s = stringRedisTemplate.opsForValue().get(key);
        //转成整数
        Integer readTime = null;
        if (StringUtils.hasText(s)) {
            readTime = Integer.parseInt(s);
            readTime += time;
        }else{
            readTime = time;
        }
        stringRedisTemplate.opsForValue().set(key, String.valueOf(readTime));
        //更新总时长
        userInfoMapper.updateTime(time,userId);
    }

    /**
     * 修改用户支付密码
     * @param payPassword
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserPayPassword(String payPassword) {
        //获取用户id
        Long userId = getUserId();
        userInfoMapper.updatePayPassword(payPassword,userId);
    }

    /**
     * 修改用户今日收入
     * @param income
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserTodayIncome(Integer income) {
        //获取用户id
        Long userId = getUserId();
        //更新缓存
        stringRedisTemplate.opsForValue().increment(RedisConstant.APP_TODAY_SCORE_KEY + userId, income);
        //更新用户信息
        userInfoMapper.updateAccount(userId, BigDecimal.valueOf(income));
    }

    /**
     * 获取用户今日收入
     * @return
     */
    @Override
    public Integer getUserTodayIncome() {
        //获取用户id
        Long userId = getUserId();
        String key = RedisConstant.APP_TODAY_SCORE_KEY + userId;

        // 从Redis获取值
        String value = stringRedisTemplate.opsForValue().get(key);

        // 处理空值情况
        if (value == null || value.trim().isEmpty()) {
            return 0;
        }

        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException e) {
            // 处理非法数字格式
            log.warn("用户今日收入数据格式异常, userId: {}, value: {}", userId, value);
            return 0;
        }
    }


    /**
     * 注销账号
     */
    @Override
    public void logout() {
        //获取用户id
        Long userId = getUserId();
        //获取用户手机号
        String phone = getPhone();
        //创建redis的key
        String key = "wait_delete:" + userId;
        //将要注销的用户id存放到redis中
        stringRedisTemplate.opsForValue().set(key, String.valueOf(userId),3,TimeUnit.DAYS);
        //根据用户id查询用户信息
        UserInfo user = userInfoMapper.getUserInfo(userId);
        //更新用户状态
        user.setStatus(BaseStatus.WAIT_DELETE.getCode());
        //更新用户信息
        userInfoMapper.update(user, phone);
    }

    /**
     * 退出
     */
    @Override
    public void exit() {
        //获取用户id
        Long userId = getUserId();
       //更新最后登入时间
        userInfoMapper.updateLastLoginTime(userId);
    }

    /**
     * 获取用户信息
     * @return
     */
    @Override
    public UserInfoVo getUserInfo() {
        //获取用户id
        Long userId = getUserId();
        //根据用户id查询用户信息
        UserInfo userInfo = userInfoMapper.getUserInfo(userId);
        //转化vo
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(userInfo, userInfoVo);
        return userInfoVo;
    }

    /**
     * 修改用户头像
     * @param avatar
     */
    @Override
    public void updateUserAvatar(String avatar) {
        //获取用户id
        Long userId = getUserId();
        userInfoMapper.updateUserAvatar(avatar, userId);
    }

    /**
     * 获取用户时长
     * @return
     */
    @Override
    public String getUserDuration() {
        //获取用户id
        Long userId = getUserId();
        if(userId == null || userId <= 0)
        {
            return "";
        }
        //创建缓存key
        String key = "today_read_time:" + userId;
        //从缓存中获取数据
        return stringRedisTemplate.opsForValue().get(key);
    }

    /**
     * 获取用户手机号
     * @return
     */
    private String getPhone() {
        LoginUser loginUser = LoginUserHolder.getLoginUser();
        if (loginUser == null) {
            throw new BaseException(ResultCodeEnum.TOKEN_EXPIRED);
        }
        //获取手机号
        return loginUser.getPhone();
    }

    /**
     * 检查并更新老用户状态（抽取为私有方法）
     */
    private void checkStatus(@NotNull UserInfo user) {
        // 检查是否被禁用
        if (BaseStatus.DISABLE.getCode().equals(user.getStatus())) {
            throw new BaseException(ResultCodeEnum.APP_ACCOUNT_DISABLED_ERROR);
        }

        // 检查是否待注销，若在Redis中则恢复启用
        if (BaseStatus.WAIT_DELETE.getCode().equals(user.getStatus())) {
            String redisKey = RedisConstant.WAIT_DELETE_KEY_PREFIX + user.getUserId();
            try {
                if (stringRedisTemplate.hasKey(redisKey)) {
                    user.setStatus(BaseStatus.ENABLE.getCode());
                    log.info("用户{}从待注销状态恢复启用", user.getUserId());
                }
            } catch (Exception e) {
                log.warn("Redis检查待注销状态失败，userId: {}", user.getUserId(), e);
            }
        }
    }

    /**
     * 获取用户id
     */
    private Long getUserId() {
        LoginUser loginUser = LoginUserHolder.getLoginUser();
        //判断登录用户是否为空
        if (loginUser == null) {
            throw new BaseException(ResultCodeEnum.TOKEN_INVALID);
        }
        return loginUser.getUserId();
    }

    /**
     * 校验验证码
     * @param code
     * @param phone
     */
    private void checkCode(String code,String phone) {
        //获取验证码
        String SsmCode = stringRedisTemplate.opsForValue().get(RedisConstant.APP_LOGIN_PREFIX + phone);

        //判断验证码是否为空
        if (!StringUtils.hasText(SsmCode)) {
            //验证码过期
            throw new BaseException(ResultCodeEnum. APP_LOGIN_CODE_EXPIRED);
        }

        //校验验证码是否准确
        if (!SsmCode.equals(SsmCode)) {
            //验证码错误
            throw new BaseException(ResultCodeEnum.APP_LOGIN_CODE_ERROR);
        }

    }


    /**
     * 创建用户
     * @return
     */
    @NotNull
    @Contract(pure = true)
    private UserInfo CreatUserInfo(@NotNull UserQuery userQuery) {
        //创建用户
        UserInfo userInfo = new UserInfo();
        String userNo = "VTR" + CodeUtil.getRandomCode(5)+ userQuery.getPhone().substring(7,11);
        userInfo.setUserNo(userNo);
        userInfo.setPhone(userQuery.getPhone());
        userInfo.setAvatar(defaultAvatar);
        userInfo.setUsername("用户" + userQuery.getPhone().substring(7,11));
        userInfo.setGender(0);
        userInfo.setBirthday(null);
        userInfo.setSignature("这个人很懒，什么都没留下");
        userInfo.setStatus(1);
        userInfo.setNightMode(0);
        userInfo.setScore(BigDecimal.valueOf(10.0));
        userInfo.setPushStatus(1);
        userInfo.setDeviceId(userQuery.getDeviceId());
        userInfo.setDeviceType(userQuery.getDeviceType());
        return userInfo;
    }




    /**
     * 校验手机号
     * @param phone
     */
    private void checkPhone(String phone) {
        log.info("校验手机号：{}", phone);
        if (phone == null || phone.length() != 11 ||
                !phone.matches("^1(3[0-9]|4[579]|5[0-35-9]|6[56]|7[0135678]|8[0-9]|9[1389])\\d{8}$")) {
            log.error("手机号格式错误");
            throw new BaseException(ResultCodeEnum.APP_PHONE_ERROR);
        }
    }

}
